package com.wolfking.jeesite.util;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ThreadPoolUtil {

    private static final Field workersField;

    private static final Field threadField;

    static {
        try {
            workersField = ThreadPoolExecutor.class.getDeclaredField("workers");
            workersField.setAccessible(true);
            threadField = ((Class<?>) ((ParameterizedType) workersField.getGenericType()).getActualTypeArguments()[0])
                    .getDeclaredField("thread");
            threadField.setAccessible(true);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    @SuppressWarnings("all")
    public static void stopThreadPoolExecutor(ThreadPoolExecutor executor) {
        executor.setCorePoolSize(0);
        executor.allowCoreThreadTimeOut(true);
        if (!executor.isTerminated()) {
            try {
                executor.shutdownNow();
            } catch (Exception e) {
            }
        }
        for (int i = 0; i < 5; i++) {
            try {
                Set workerSet = (Set) workersField.get(executor);
                CopyOnWriteArraySet copyOnWriteArraySet = new CopyOnWriteArraySet(workerSet);
                for (Object worker : copyOnWriteArraySet) {
                    try {
                        Thread thread = (Thread) threadField.get(worker);
                        thread.stop();
                    } catch (Throwable e) {
                        log.warn("stop thread error");
                    }
                }
                log.info("force stop the thread pool success");
                break;
            } catch (IllegalArgumentException | IllegalAccessException e) {
                log.error("reflect error", e);
                break;
            } catch (ConcurrentModificationException e) {
                if (i == 4) {
                    log.warn("stop thread error", e);
                    break;
                }
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException ee) {
                    log.warn("stop thread ConcurrentModificationException sleep InterruptedException error", ee);
                }
            }
        }
    }
}
